﻿using System;
using System.Collections.Generic;
using Simp.Model.CoreTransformations;

namespace Simp.Model.CoreTransformations
{
	/// <summary>Unwind <see cref="ScopeExpression"/>, replacing them by their equivalent.</summary>
	/// <remarks>
	/// This transformation uses <see cref="ExpressionBindingTransformation"/> tolerating failures.  Therefore, it can be
	/// called before every expression has been bound.
	/// </remarks>
	public class UnscopeTransformation : IExpressionTransformation
	{
		#region IExpressionTransformation Members
		IExpression IExpressionTransformation.Tranform(IExpression expression)
		{
			CompositeExpression composite = expression as CompositeExpression;

			if (composite == null)
			{	//	End of recursion:  we hit a leaf
				return null;
			}
			else
			{
				ScopeExpression scope = composite.InnerExpression as ScopeExpression;

				if (scope != null)
				{
					return UnwindScope(composite.ParameterList);
				}
				else
				{
					return ExpressionHelper.TranformComposite(true, this, composite);
				}
			}
		}
		#endregion

		private IExpression UnwindScope(IExpression[] expressionList)
		{
			if (expressionList.Length > 0)
			{
				IDictionary<string, IExpression> knownExpressionMap = new Dictionary<string, IExpression>();

				//	Pass through each custom definition and integrate them
				for (int i = 0; i != expressionList.Length - 1; ++i)
				{
					CustomExpression custom;
					CompositeExpression composite = ExpressionHelper.TryGetComposite(expressionList[i], out custom);

					if (composite == null)
					{	//	Should be a custom expression since it's a definition
						return null;
					}
					else
					{
						string name = ((INamedExpression)custom).Name;
						IExpressionTransformation transformation =
							new ExpressionBindingTransformation(true, knownExpressionMap);
						IExpression transformedExpression = ExpressionHelper.Tranform(false, composite, transformation);

						if (knownExpressionMap.ContainsKey(name))
						{	//	Can't have twice the same name
							return null;
						}
						else
						{	//	Add the resolved expression to the known expression
							knownExpressionMap.Add(name, transformedExpression);
						}
					}
				}

				IExpressionTransformation returnTransformation =
					new ExpressionBindingTransformation(true, knownExpressionMap);
				IExpression returnExpression = expressionList[expressionList.Length - 1];
				IExpression transformedReturnExpression =
					ExpressionHelper.Tranform(false, returnExpression, returnTransformation);

				return transformedReturnExpression;
			}
			else
			{
				return null;
			}
		}
	}
}